using System.Linq;
using Microsoft.Extensions.Caching.Memory;
using Quant.Data;
using Quant.Entities;
using Quant.Services;

namespace Quant.Services
{
    public class CoreEngine
    {
        private readonly BinanceService _binance;
        //private readonly AppDbContext _db;
        private const int HistoricalDays = 15;
        private readonly IMemoryCache _cache;
        private const string VolumeCacheKey = "HistoricalVolume";

        public CoreEngine(BinanceService binance,
            //AppDbContext db, 
            IMemoryCache cache)
        {
            _binance = binance;
            //_db = db;
            _cache = cache;
        }

        public async Task CheckAndTradeAsync()
        {
            var strategy = new StrategyConfig();// _db.StrategyConfigs.First();
            var symbol = strategy.Symbol;

            // 获取当前5分钟成交量
            var currentVol = await _binance.GetCurrentVolumeAsync(symbol, "5m");

            var avgVol = await CalculateDayAverageVolume(symbol, HistoricalDays);

            // 获取系统阈值参数
            var threshold = 3; //_db.SystemSettings.First(s => s.ParamName == "VolumeThreshold").ParamValue;

            if (currentVol > avgVol * threshold)
            {
                var lastPrice = await GetLastPrice(symbol);
                var direction = await DetermineDirection(symbol);
                await _binance.PlaceOrderAsync(strategy, lastPrice, direction);

                //// 记录交易
                //_db.TradeRecords.Add(new TradeRecord
                //{
                //    Direction = direction,
                //    Quantity = strategy.OrderMode == 1
                //        ? strategy.FixedAmount / lastPrice
                //        : strategy.PositionRatio * await _binance.GetAccountBalance(),
                //    ExecutedPrice = lastPrice,
                //    Leverage = strategy.Leverage,
                //    Symbol = symbol
                //});
                //await _db.SaveChangesAsync();
            }
        }

        /// <summary>
        /// 计算15日平均成交量
        /// </summary>
        /// <param name="symbol"></param>
        /// <param name="dayNum"></param>
        /// <returns></returns>
        private async Task<decimal> CalculateDayAverageVolume(string symbol, int dayNum = 15)
        {
            if (!_cache.TryGetValue(VolumeCacheKey, out List<decimal> historicalVolumes))
            {
                historicalVolumes = new List<decimal>();
                var endTime = DateTime.UtcNow;

                for (int i = 0; i < dayNum; i++)
                {
                    var startTime = endTime.AddDays(-1);
                    var klines = await _binance.GetHistoricalKlinesAsync(symbol, "1d", startTime, endTime);
                    historicalVolumes.Add(klines.Average(k => k.Volume));
                    endTime = startTime;
                }
                _cache.Set(VolumeCacheKey, historicalVolumes, TimeSpan.FromHours(1));
            }
            var avg = historicalVolumes.Average();
            //string direction = historicalVolumes.FirstOrDefault() - historicalVolumes.LastOrDefault() > 0 ? "" : "";
            return avg;
        }

        private async Task<decimal> GetLastPrice(string symbol)
        {
            return await _binance.GetCurrentPriceAsync(symbol);
        }

        private async Task<string> DetermineDirection(string symbol)
        {
            var endTime = DateTime.UtcNow;
            var startTime = endTime.AddMinutes(-15);
            var klines = await _binance.GetHistoricalKlinesAsync(symbol, "5m", startTime, endTime);

            if (klines.Count >= 3 &&
                klines[^1].ClosePrice > klines[^2].ClosePrice &&
                klines[^2].ClosePrice > klines[^3].ClosePrice)
            {
                return "BUY";
            }

            if (klines.Count >= 3 &&
                klines[^1].ClosePrice < klines[^2].ClosePrice &&
                klines[^2].ClosePrice < klines[^3].ClosePrice)
            {
                return "SELL";
            }

            return "HOLD";
        }
    }
}